#pragma once

#include <iostream>
#include <math.h>
using namespace std;
template <class T>
class Interval
{
private:
	T upper;
	T lower;
public:

	Interval(void)
	{
		lower = 0;
		upper = 0;
	}

	Interval( T value, double percentage )
	{
		lower = value - value * percentage / 100;
		upper = value + value * percentage / 100;
	}

	~Interval(void)
	{
	}

	friend ostream& operator<<( ostream &out, Interval<T> &interval )
	{
		out << "[" << interval.GetLower() << "," << interval.GetUpper() << "]";
		return out;
	}

	friend Interval<T> operator+( Interval<T> &lop, Interval<T> &rop )
	{
		Interval<T> dummy;
		dummy.SetUpper( lop.GetUpper() + rop.GetUpper() );
		dummy.SetLower( lop.GetLower() + rop.GetLower() );
		return dummy;
	}

	friend Interval<T> operator-( Interval<T> &lop, Interval<T> &rop )
	{
		Interval<T> dummy;
		dummy.SetUpper( lop.GetUpper() - rop.GetLower() );
		dummy.SetLower( lop.GetLower() - rop.GetUpper() );
		return dummy;
	}

	friend Interval<T> operator*( Interval<T> &lop, Interval<T> &rop )
	{
		Interval<T> dummy;
		T dummyT;

		dummyT = max( (lop.GetLower() * rop.GetLower()), (lop.GetLower() * rop.GetUpper()) );
		dummyT = max( dummyT, (lop.GetUpper() * rop.GetLower()) );
		dummyT = max( dummyT, (lop.GetUpper() * rop.GetUpper()) );
		dummy.SetUpper( dummyT );

		dummyT = min( (lop.GetLower() * rop.GetLower()), (lop.GetLower() * rop.GetUpper()) );
		dummyT = min( dummyT, (lop.GetUpper() * rop.GetLower()) );
		dummyT = min( dummyT, (lop.GetUpper() * rop.GetUpper()) );
		dummy.SetLower( dummyT );

		return dummy;
	}

	friend Interval<T> operator/( Interval<T> &lop, Interval<T> &rop )
	{
		Interval<T> dummy;
		T dummyT;

		dummyT = max( (lop.GetLower() / rop.GetLower()), (lop.GetLower() / rop.GetUpper()) );
		dummyT = max( dummyT, (lop.GetUpper() / rop.GetLower()) );
		dummyT = max( dummyT, (lop.GetUpper() / rop.GetUpper()) );
		dummy.SetUpper( dummyT );

		dummyT = min( (lop.GetLower() / rop.GetLower()), (lop.GetLower() / rop.GetUpper()) );
		dummyT = min( dummyT, (lop.GetUpper() / rop.GetLower()) );
		dummyT = min( dummyT, (lop.GetUpper() / rop.GetUpper()) );
		dummy.SetLower( dummyT );

		return dummy;
	}

	T mean()
	{
		return (lower+upper)/2;
	}

	double relative_error()
	{
		return abs(upper-lower)/mean();
	}

	T absolute_error()
	{
		return abs(lower-upper);
	}

	T GetUpper() { return this->upper; }
	T GetLower() { return this->lower; }

	void SetUpper( T upper ) { this->upper = upper; }
	void SetLower( T lower ) { this->lower = lower; }


};

